#!/usr/bin/env ruby
  
  require 'fox16'
  require 'date'
  require './Bd'
  
  include Fox
  
  class TableWindow < FXMainWindow
  
  

 # Inserta en la estructura de consulta el valor correspondiente de la tabla de fila=fila y columna=columna
 # Tiene en cuenta los tipos del campotamanio
  def setqry(fila,columna,valor)
    campo=@campos[columna] #El vector @campos contine todos los campos de la consulta
    return nil if (@qry.at(campo,"tamanio")==0) # si no es visible=> no se actualiza
    # puts "esta #{Bd::ValBooleanos.split(" ").include?(valor)} "
    if (@qry.at(campo,:tipo)=="boolean" &&  Bd::ValBooleanos.split(" ").include?(valor))
      @qry.at(campo,:new,fila) { Bd::ValTrue.split(" ").include?(valor) ? 't':'f'}
    else !(@qry.at(campo,:tipo)=="boolean")
      @qry.at(campo,:new,fila) {valor}
    end
  end
  
#completa el contenido de una celda acorde con el tipo de datos (booleano o no)  
  def put_dato (campo,nf,nc,value)
    if @qry.at(campo,:tipo)=="boolean"
      @table.setItemIcon(nf, nc, (value=="t"  ? @icontrue :@iconfalse))
    else
      @table.setItemText(nf, nc, value)  #value es el valor de la columna
    end
    #se alinea a la izquierda o a la derecha según el tipo de datos
    #puts "el campo #{campo} tiene el tipo #{@qry.at(campo,:tipo)}"
    @table.getItem(nf,nc).justify = case (@qry.at(campo,:tipo))
                                      when 'character','text' then FXTableItem::LEFT
                                      when 'integer','numeric','real' then FXTableItem::RIGHT
                                      else FXTableItem::CENTER_X
                                      end
     
    @table.getItem(nf,nc).borders = FXTableItem::TBORDER|FXTableItem::RBORDER|FXTableItem::BBORDER|FXTableItem::LBORDER unless  (@qry.at(campo,:c_ajena,nc)).nil?  
                                         
  end
  
  # Rellena y crea la tabla conforme a lo que pone la consulta 
  def filltable 
    @table.setTableSize(@nf, @nc)   #nf y nc se rellenan en inidatos
    
    @campos.each_with_index do |campo,nc| #por cada índice de los campos (c es el nombre del campo de la cnsulta)
      @table.setColumnText(nc,@qry.campos[campo][:iu]) # Titulo de las columnas
      @table.setColumnWidth(nc,@qry.at(campo,:tamanio).to_i*10)
      @qry.at(campo,:new).each_with_index do |value,nf|  #nf es la fila. Value es el valor del campo de la consulta
        put_dato campo, nf,nc,value
        @table.setRowText(nf,(nf + 1).to_s + (@qry.getcambios(campo,nf,:actualiza_uno).empty? ? "": "  *")) if nc==0
      end
    end
  end


  def inidatos
    @icontrue=Bd.makeIcon(getApp(), "true.png") unless @icontrue 
    @iconfalse=Bd.makeIcon(getApp(),"false.png") unless @iconfalse
    @qry=Bd.new("MOD_propiedades");
    @campos=@qry.campos.keys
    @nc=@campos.length #número de columnas
    @qry.run('')  #obtenemos todas las filas de la consulta
    #puts @campos
    @nf=@qry.at(@campos[0],:new).length if @nc.to_i>0  #número de filas (todas las colunas tienen las mismas)
  end
  
  def formateatabla
    @table.visibleRows = @nf
    @table.visibleColumns = @nc
    @table.setBackColor(FXRGB(255, 255, 255))
    @table.setCellColor(0, 0, FXRGB(255, 255, 255))
    @table.setCellColor(0, 1, FXRGB(255, 240, 240))
    @table.setCellColor(1, 0, FXRGB(240, 255, 240))
    @table.setCellColor(1, 1, FXRGB(240, 240, 255))
  end

  def CmdGuardar(fila,op=:todo)
    #puts "Item del menu#{item}"
    
    @qry.save fila,op
    unless @qry.msgerror=='OK' || @qry.msgerror.empty? 
      FXMessageBox.warning(self,MBOX_OK,"No se han podido salvar los cambios",@qry.msgerror)
      return
    end
    if op==:actualiza_uno #solo si se actualiza uno, se guarda dicho registro pero no se recarga de la base de datos. Se pone old=new
      #@campos.each {|c| puts "fila = #{fila} campo=#{c}"}
      #@campos.each {|c| puts "fila = #{fila} campo=#{c}@qry.at(c,:new,fila)= #{@qry.at(c,:new,fila)}"} 
      @campos.each{|c| @qry.at(c,:old,fila){@qry.at(c,:new,fila)}} #la fila actual hacemos que coincida el new con el old (como si lo hubiesemos leido de la bD)
    else
      inidatos  
    end
    filltable
    
  end

  def cmdInsertar()
    @qry.save()
    dlg = FXDialogBox.new(self, "Insertar")
     # Set up its content          s
     
     
    frame = FXHorizontalFrame.new(dlg, LAYOUT_FILL_X|LAYOUT_FILL_Y)
    FXLabel.new(frame, "Rows:", nil, LAYOUT_SIDE_LEFT|LAYOUT_CENTER_Y)
    rows = FXTextField.new(frame, 5,
    :opts => JUSTIFY_RIGHT|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_LEFT|LAYOUT_CENTER_Y)
    FXLabel.new(frame, "Columns:", nil, LAYOUT_SIDE_LEFT|LAYOUT_CENTER_Y)
    cols = FXTextField.new(frame, 5,
    :opts => JUSTIFY_RIGHT|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_LEFT|LAYOUT_CENTER_Y)
    FXButton.new(frame, "Cancel", nil, dlg, FXDialogBox::ID_CANCEL,
    FRAME_RAISED|FRAME_THICK|LAYOUT_SIDE_LEFT|LAYOUT_CENTER_Y)
    FXButton.new(frame, " OK ", nil, dlg, FXDialogBox::ID_ACCEPT,
    FRAME_RAISED|FRAME_THICK|LAYOUT_SIDE_LEFT|LAYOUT_CENTER_Y)
    # Initialize the text fields' contents
    oldnr, oldnc = @table.numRows, @table.numColumns
    rows.text = oldnr.to_s
    cols.text = oldnc.to_s
      # FXDialogBox#execute will return non-zero if the user clicks OK
    if dlg.execute != 0
      nr, nc = rows.text.to_i, cols.text.to_i
      nr = 0 if nr < 0
      nc = 0 if nc < 0
    end  
  end
  
  def initialize(app)
  # Call the base class initializer first
    super(app, "Tabla generica", :opts => DECOR_ALL)
    # Tooltip
    tooltip = FXToolTip.new(getApp())
  
    # Menubar
    menubar = FXMenuBar.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
  
    # Separator
    FXHorizontalSeparator.new(self, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|SEPARATOR_GROOVE)
  
    # Contents
    contents = FXVerticalFrame.new(self, LAYOUT_SIDE_TOP|FRAME_NONE|LAYOUT_FILL_X|LAYOUT_FILL_Y)
  
    frame = FXVerticalFrame.new(contents,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y, :padding => 0)
  
    inidatos()
    # Table
    @table = FXTable.new(frame, :opts => TABLE_COL_SIZABLE|TABLE_ROW_SIZABLE|LAYOUT_FILL_X|LAYOUT_FILL_Y,
    :padding => 2)
    
    filltable #rellenamos la tabla

    
  # Inicializamos eventos de la tabla
  @table.connect(SEL_RIGHTBUTTONRELEASE) do |sender, sel, event|
      unless event.moved?
        fila = sender.rowAtY( event.win_y)
        columna=sender.colAtX(event.win_x)
        unless (fila==-1 || columna==-1) #hay un item seleccionado
          #opciones_fila(fila,columna)
          @table.setCurrentItem(fila,columna,true)
          @table.selectItem(fila,columna,true)
          FXMenuPane.new(self) do |menu_pane|
            upd = FXMenuCommand.new(menu_pane, "Guardar Registro")
            upd.connect(SEL_COMMAND) { CmdGuardar(fila, :actualiza_uno ) }
            upd = FXMenuCommand.new(menu_pane, "Guardar Todos")
            upd.connect(SEL_COMMAND) { CmdGuardar(fila, :actualiza_todo) }
            del = FXMenuCommand.new(menu_pane, "Eliminar el Registro")
            del.connect(SEL_COMMAND) { cmdEliminar(fila,:elimina_uno) }
            del = FXMenuCommand.new(menu_pane, "Eliminar Todos los Registro")
            del.connect(SEL_COMMAND) { cmdEliminar(fila,:elimina_todos) }
            ins = FXMenuCommand.new(menu_pane, "Insertar Registro")
            ins.connect(SEL_COMMAND) { cmdInsertar(fila,:insertar)}
            menu_pane.create
            menu_pane.popup(nil, event.root_x, event.root_y)
            #app.runModalWhileShown(menu_pane)
          end
         end
        end
     end
  
  
  @table.connect(SEL_COMMAND) do |sender, sel, dato|
    col,fil=dato.col,dato.row
    campo=@campos[col]
    @table.disableItem(fil,col) unless @qry.at(campo,:c_ajena).empty? 
    
    
  end
  
  @table.connect(SEL_CHANGED) do |sender, sel, dato|
    col,fil=dato.col,dato.row
    campo=@campos[col]
    @table.enableItem(fil,col) unless @qry.at(campo,:c_ajena).empty?
    
  end
  
  @table.connect(SEL_REPLACED) do |sender, sel, dato| #cada vez que hacemos un cambio en el campo de la tabla
     col=dato.fm.col
     fil=dato.fm.row
    
     campo=@campos[col]

     setqry(fil,col,@table.getItemText(fil,col))
     
     #@qry.save(fil) 
       
     @table.setTableSize(@nf, @nc)
     filltable
     @table.setCurrentItem(fil,col,true)
     @table.selectItem(fil,col,true)
   end
   
   @table.connect(SEL_VERIFY) do |sender, sel, tentative|
      #if tentative =~ /^[a-zA-Z][a-zA-Z0-9]*$/
      if ['true','false','ok','ko','t','f'].include?(tentative)
        puts tentative
        false
      else
        true
    end
end
  
  # File Menu
  filemenu = FXMenuPane.new(self)
  FXMenuCommand.new(filemenu, "&Quit\tCtl-Q", nil, getApp(), FXApp::ID_QUIT)
  FXMenuTitle.new(menubar, "&File", nil, filemenu)
  
  # Options Menu
  tablemenu = FXMenuPane.new(self)
  FXMenuCheck.new(tablemenu, "Horizontal grid", @table, FXTable::ID_HORZ_GRID)
  FXMenuCheck.new(tablemenu, "Vertical grid", @table, FXTable::ID_VERT_GRID)
  FXMenuTitle.new(menubar, "&Options", nil, tablemenu)
  
  # Manipulations Menu
  manipmenu = FXMenuPane.new(self)
  FXMenuCommand.new(manipmenu, "Delete Column\tCtl-C", nil,
  @table, FXTable::ID_DELETE_COLUMN)
  FXMenuCommand.new(manipmenu, "Delete Row\tCtl-R", nil,
  @table, FXTable::ID_DELETE_ROW)
  FXMenuCommand.new(manipmenu, "Insert Column\tCtl-Shift-C", nil,
  @table, FXTable::ID_INSERT_COLUMN)
  FXMenuCommand.new(manipmenu, "Insert Row\tCtl-Shift-R", nil,
  @table, FXTable::ID_INSERT_ROW)
  FXMenuCommand.new(manipmenu, "Resize table...").connect(SEL_COMMAND, method(:onCmdResizeTable))
  FXMenuTitle.new(menubar, "&Manipulations", nil, manipmenu)
  
  # Selection Menu
  selectmenu = FXMenuPane.new(self)
  FXMenuCommand.new(selectmenu, "Select All", nil, @table, FXTable::ID_SELECT_ALL)
  FXMenuCommand.new(selectmenu, "Select Cell", nil, @table, FXTable::ID_SELECT_CELL)
  FXMenuCommand.new(selectmenu, "Select Row", nil, @table, FXTable::ID_SELECT_ROW)
  FXMenuCommand.new(selectmenu, "Select Column", nil, @table, FXTable::ID_SELECT_COLUMN)
  FXMenuCommand.new(selectmenu, "Deselect All", nil, @table, FXTable::ID_DESELECT_ALL)
  FXMenuCommand.new(selectmenu, "Cut to Clipboard", nil, @table, FXTable::ID_CUT_SEL)
  FXMenuCommand.new(selectmenu, "Copy to Clipboard", nil, @table, FXTable::ID_COPY_SEL)
  FXMenuCommand.new(selectmenu, "Paste from Clipboard", nil, @table, FXTable::ID_PASTE_SEL)
  FXMenuCommand.new(selectmenu, "Delete", nil, @table, FXTable::ID_DELETE_SEL)
  FXMenuTitle.new(menubar, "&Selection", nil, selectmenu)
  end
  
  # Resize the table
  def onCmdResizeTable(sender, sel, ptr)
  # Create an empty dialog box
  dlg = FXDialogBox.new(self, "Resize Table")
  
  # Set up its contents
  frame = FXHorizontalFrame.new(dlg, LAYOUT_FILL_X|LAYOUT_FILL_Y)
  FXLabel.new(frame, "Rows:", nil, LAYOUT_SIDE_LEFT|LAYOUT_CENTER_Y)
  rows = FXTextField.new(frame, 5,
  :opts => JUSTIFY_RIGHT|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_LEFT|LAYOUT_CENTER_Y)
  FXLabel.new(frame, "Columns:", nil, LAYOUT_SIDE_LEFT|LAYOUT_CENTER_Y)
  cols = FXTextField.new(frame, 5,
  :opts => JUSTIFY_RIGHT|FRAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_LEFT|LAYOUT_CENTER_Y)
  FXButton.new(frame, "Cancel", nil, dlg, FXDialogBox::ID_CANCEL,
  FRAME_RAISED|FRAME_THICK|LAYOUT_SIDE_LEFT|LAYOUT_CENTER_Y)
  FXButton.new(frame, " OK ", nil, dlg, FXDialogBox::ID_ACCEPT,
  FRAME_RAISED|FRAME_THICK|LAYOUT_SIDE_LEFT|LAYOUT_CENTER_Y)
  
  # Initialize the text fields' contents
  oldnr, oldnc = @table.numRows, @table.numColumns
  rows.text = oldnr.to_s
  cols.text = oldnc.to_s
  
  # FXDialogBox#execute will return non-zero if the user clicks OK
  if dlg.execute != 0
  nr, nc = rows.text.to_i, cols.text.to_i
  nr = 0 if nr < 0
  nc = 0 if nc < 0
  @table.setTableSize(nr, nc)
    filltable
  if dlg.execute != 0
    puts "dialogo ejecutado una vez mas"
    
  end  
  end
  return 1
  end
  
  # Create and show this window
  def create
  super
  show(PLACEMENT_SCREEN)
  end
  end
  
  # Start the whole thing
  if __FILE__ == $0
  # Make application
  application = FXApp.new("TableApp", "FoxTest")
  
  # Make window
  TableWindow.new(application)
  
  # Create app
  application.create
  
  # Run
  application.run
  end